package nyist.media.service.impl;

import nyist.media.bean.auth.MenuAuthListBean;
import nyist.media.bean.auth.MenuOptionBean;
import nyist.media.bean.auth.MenuTreeBean;
import nyist.media.entity.admin.MenuAuth;
import nyist.media.exception.BusinessException;
import nyist.media.mapper.IndexMapper;
import nyist.media.page.ApiResult;
import nyist.media.page.AppPage;
import nyist.media.repository.MenuAuthRepository;
import nyist.media.service.MenuAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class MenuAuthServiceImpl extends BaseServiceImpl<MenuAuth, Long> implements MenuAuthService {

    @Autowired
    private MenuAuthRepository menuAuthRepository;
    @Autowired
    private IndexMapper indexMapper;

    @Autowired
    public void setBaseRepository(MenuAuthRepository baseRepository) {
        super.setBaseRepository(baseRepository);
    }

    @Override
    public AppPage<MenuAuthListBean> findPage(Long parentId, PageRequest pageable) {
        Page<MenuAuth> p = menuAuthRepository.findPage(parentId, pageable);
        List<MenuAuthListBean> list = p.getContent().stream().map(MenuAuthListBean::new).collect(Collectors.toList());
        return new AppPage<>(pageable, p.getTotalElements(), p.getTotalPages(), list);
    }

    @Override
    public MenuAuthListBean getInfo(Long id) {
        return new MenuAuthListBean(menuAuthRepository.findOne(id));
    }

    @Override
    @CacheEvict(value = MenuTreeBean.REDIS_CACHE_ALL_AUTHORITY_KEY, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public void update(MenuAuthListBean param) throws BusinessException {
        MenuAuth auth = menuAuthRepository.findOne(param.getId());
        if (param.getParentId() != null) {
            if (param.getParentId().equals(param.getId())) {
                throw new BusinessException(ApiResult.ILLEGAL_PARAMS, "上级菜单设置错误，不能绑定自己");
            }
            MenuAuth parent = menuAuthRepository.findOne(param.getParentId());
            String id = param.getId().toString();
            if (Stream.of(parent.getTreePath().split(MenuAuth.SEPARATOR)).anyMatch(i -> i.equals(id))) {
                throw new BusinessException(ApiResult.ILLEGAL_PARAMS, "上级菜单设置错误，不能绑定自己的子菜单");
            }
            auth.setParent(parent);
        } else {
            auth.setParent(null);
        }
        setGrade(auth);

        auth.setAuthority(param.getAuthority());
        auth.setEnabled(param.isEnabled());
        auth.setType(param.getType());
        auth.setName(param.getName());
        auth.setShowMenu(param.isShowMenu());
        auth.setHref(param.getHref());
        auth.setIcon(param.getIcon());
        auth.setOrders(param.getOrders());
        menuAuthRepository.save(auth);
    }

    @Override
    @CacheEvict(value = MenuTreeBean.REDIS_CACHE_ALL_AUTHORITY_KEY, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public void save(MenuAuthListBean param) throws BusinessException {
        MenuAuth auth = new MenuAuth();
        auth.setType(param.getType());
        auth.setName(param.getName());
        auth.setEnabled(param.isEnabled());
        auth.setShowMenu(param.isShowMenu());
        auth.setHref(param.getHref());
        auth.setIcon(param.getIcon());
        auth.setOrders(param.getOrders());
        if (param.getParentId() != null) {
            auth.setParent(menuAuthRepository.findOne(param.getParentId()));
        }
        auth.setAuthority(param.getAuthority());
        setGrade(auth);
        menuAuthRepository.save(auth);
    }

    /**
     * 设置树路径和层级
     *
     * @param auth 菜单权限
     */
    private void setGrade(MenuAuth auth) {
        if (auth.getParent() != null) {
            auth.setTreePath(auth.getParent().getTreePath() + auth.getParent().getId() + MenuAuth.SEPARATOR);
            auth.setGrade(auth.getParent().getGrade() + 1);
        } else {
            auth.setTreePath(MenuAuth.SEPARATOR);
            auth.setGrade(0);
        }
    }

    @Override
    @CacheEvict(value = MenuTreeBean.REDIS_CACHE_ALL_AUTHORITY_KEY, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) throws BusinessException {
        MenuAuth auth = menuAuthRepository.findOne(id);
        if (menuAuthRepository.countAllByParent(auth) > 0) {
            throw new BusinessException(ApiResult.ILLEGAL_PARAMS, "数据已被关联，无法删除");
        }
        menuAuthRepository.delete(auth);
    }

    @Override
    public List<MenuOptionBean> findOptions() {
        return menuAuthRepository.findMenuList(MenuAuth.Type.MENU.ordinal())
                .stream().map(MenuOptionBean::new)
                .collect(Collectors.toList());
    }

    @Override
    public List<MenuTreeBean> findRoot() {
        return menuAuthRepository.findAllByParentIsNull().stream().map(MenuTreeBean::new).collect(Collectors.toList());
    }

    @Override
    @Cacheable(MenuTreeBean.REDIS_CACHE_ALL_AUTHORITY_KEY)
    public List<MenuTreeBean> menuList() {
        return indexMapper.findIndexMenu(null);
    }

    @Override
    public MenuAuth switchStatus(Long id) {
        MenuAuth menuAuth = menuAuthRepository.findOne(id);
        menuAuth.setEnabled(!menuAuth.isEnabled());
        return menuAuthRepository.save(menuAuth);
    }

    @Override
    public MenuAuth show(Long id) {
        MenuAuth menuAuth = menuAuthRepository.findOne(id);
        menuAuth.setShowMenu(!menuAuth.isShowMenu());
        return menuAuthRepository.save(menuAuth);
    }
}
